package com.gee.spring.boot.starter.opengemini.core.domain;

import com.gee.spring.boot.starter.opengemini.core.util.ReflectionUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static com.gee.spring.boot.starter.opengemini.core.constant.StrConstant.EMPTY;
import static com.gee.spring.boot.starter.opengemini.core.constant.StrConstant.UNDERLINE;

/**
 * @author gepengjun
 * @since 2024/4/28 14:05
 */
public class MeasurementInfo {

    private String measurement;

    private List<String> measurementSuffixFieldList;

    private String database;

    private String timeFuncAlias;

    private Field timeField;

    private String retentionPolicy;

    private Field mapColumnField;

    private Field databaseSuffixField;


    //columnName  fieldName
    private final Map<String, String> columnFieldMap = new HashMap<>();

    private final Map<String, ColumnInfo> fieldColumnInfoMap = new HashMap<>();

    public MeasurementInfo(String measurement) {
        this.measurement = measurement;
    }

    public Field getField(String column){
        String fieldName = columnFieldMap.get(column);
        if (fieldName == null){
            return null;
        }
        return fieldColumnInfoMap.get(fieldName).getField();
    }

    public ColumnInfo getColumnInfoByFieldName(String fieldName){
        ColumnInfo columnInfo = fieldColumnInfoMap.get(fieldName);
        if (columnInfo == null){
            throw new RuntimeException("通过字段名称查询列信息未找到， 字段名称: " + fieldName);
        }
        return columnInfo;
    }
    public ColumnInfo getColumnInfoByColumnName(String columnName){
        ColumnInfo columnInfo = fieldColumnInfoMap.get(columnFieldMap.get(columnName));
        if (columnInfo == null){
            throw new RuntimeException("通过列名称查询列信息未找到， 列名称: " + columnName);
        }
        return columnInfo;
    }

    public String getMeasurement(Object obj) {
        if (CollectionUtils.isEmpty(measurementSuffixFieldList) || obj == null){
            return measurement;
        }
        return measurementSuffixFieldList.stream()
                .map(field -> ReflectionUtil.getFieldValue(obj, ReflectionUtil.getField(obj.getClass(), field)))
                .filter(Objects::nonNull)
                .map(Object::toString)
                .collect(Collectors.joining(UNDERLINE, measurement + UNDERLINE, EMPTY));
    }

    public String getMeasurementBySuffixValue(Object ... measurementSuffixValueList) {
        if (ArrayUtils.isEmpty(measurementSuffixValueList)){
            return measurement;
        }
        return Arrays.stream(measurementSuffixValueList)
                .map(Object::toString)
                .collect(Collectors.joining(UNDERLINE, measurement + UNDERLINE, EMPTY));
    }

    public void setMeasurement(String measurement) {
        this.measurement = measurement;
    }

    public Map<String, String> getColumnFieldMap() {
        return columnFieldMap;
    }

    public Map<String, ColumnInfo> getFieldColumnInfoMap() {
        return fieldColumnInfoMap;
    }

    public String getTimeFuncAlias() {
        return timeFuncAlias;
    }

    public void setTimeFuncAlias(String timeFuncAlias) {
        this.timeFuncAlias = timeFuncAlias;
    }

    public Field getTimeField() {
        return timeField;
    }

    public void setTimeField(Field timeField) {
        this.timeField = timeField;
    }

    public String getDatabase(Object obj) {
        if (databaseSuffixField == null || obj == null){
            return database;
        }
        Object fieldValue = ReflectionUtil.getFieldValue(obj, databaseSuffixField);
        if (fieldValue == null){
            return database;
        }
        return database + UNDERLINE + fieldValue;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public String getRetentionPolicy() {
        return retentionPolicy;
    }

    public void setRetentionPolicy(String retentionPolicy) {
        this.retentionPolicy = retentionPolicy;
    }

    public Field getMapColumnField() {
        return mapColumnField;
    }

    public void setMapColumnField(Field mapColumnField) {
        this.mapColumnField = mapColumnField;
    }

    public List<String> getMeasurementSuffixFieldList() {
        return measurementSuffixFieldList;
    }

    public void setMeasurementSuffixFieldList(List<String> measurementSuffixFieldList) {
        this.measurementSuffixFieldList = measurementSuffixFieldList;
    }

    public Field getDatabaseSuffixField() {
        return databaseSuffixField;
    }

    public void setDatabaseSuffixField(Field databaseSuffixField) {
        this.databaseSuffixField = databaseSuffixField;
    }
}
